true currencies
#Stable_Coin
2019年1月3日にTrueUSDのコントラクトがアップデートされた。これによりコントラクトアドレスが変更になり、ソースコードも大幅に変更された。
参考:TrueUSD Smart Contract Upgrade Note
true-currencies実装
TrueUSDの新実装を調べる。
リポジトリ:https://github.com/trusttoken/true-currencies
Etherscan: https://etherscan.io/token/0x0000000000085d4780B73119b644AE5ecd22b376
なお、古い実装の解説はTrueUSDを参照ください。
TrueUSD自体の説明もあります。
スマートコントラクトのアップグレード方法の変更
https://gyazo.com/48377ffe28058d739bd5e6ec33a9677f
塗り潰した矢印はコントラクトの継承を表しています
普通の矢印はaddressの向き先を表しています
上図は旧スマートコントラクトと新スマートコントラクトでのコントラクトアップグレードの違いを示しています。
旧スマートコントラクトでのアップグレード方法
CanDelegateのdelegateストレージ変数を設定することで、古いスマートコントラクトが実行された時に新しいコントラクトに処理が委譲されます(delegateが設定されていない場合は委譲されない)
これが旧コントラクトのアップグレード方法
TrueUSDアップデートのアナウンス後、delegateストレージ変数には新しいTrueUSDのコントラクトアドレスが設定されています
Etherscanにて旧コントラクトのdelegateを調べると、新TrueUSDのアドレスが設定されていることが分かる
エンドユーザや仮想通貨交換所は、旧コントラクトを叩いても新コントラクトに処理が委譲されますが、最初から新コントラクトを叩いた方がGas feeを節約できます
実質的に、TrueUSDアップグレードのたびにアプリケーションのアップデートが求められます
新スマートコントラクトでの委譲方法
Proxy/OwnedUpgradeabilityProxyのimplementationPositionストレージ変数に設定されたコントラクトに常に処理が委譲されます
implementationをcallすることによって委譲先のコントラクトアドレスを取得できます
proxyOwner限定で実行可能なupgradeToを実行することによって委譲先のコントラクトアドレスを変更できます
エンドユーザや仮想通貨交換所は、TrueUSDがアップグレードしても実行するコントラクトアドレスを変更する必要がありません
以下、重要な2つのコントラクトコードの解説です。
Proxy/OwnedUpgradeabilityProxy.sol
TrueUSDやTrueGBPのフロントエンドになるコントラクトで、このコントラクトのfallback関数からdelegatecallで実装コントラクトの各種関数(transfer等)を呼ぶようになっている。こうすることで、実装コントラクトのアップグレードがあってもフロントエンドのコントラクトアドレスを変更することなく新しいコントラクトを利用できるようになる。
また、delegatecallによる呼び出しをすることで、storage変数の保存先コントラクトがTrueUSD.sol等の実装クラスからこのコントラクトになるので、アップグレードをしてもstorageの移行をする必要がない。
実装: OwnedUpgradeabilityProxy.sol
参考: Delegatecall / Callcode and Libraries
→ これを Proxy Pattern という
→ このコントラクトのおかげでエンドユーザーのUXが改善される!
function implementation() public view returns (address impl)
このimplementation関数によって実装コントラクトのコントラクトアドレスが得られる。
fallback関数では、この関数で得られるアドレスに対してdelegatecallを実行している。
function upgradeTo(address implementation) external onlyProxyOwner
このupgradeTo関数によって実装コントラクトのアップグレードができる。
ProxyStorage.sol
全てのストレージ変数はProxyStorage.solに定義されている。他の派生コントラクトではストレージ変数を定義しない。そうすることでコントラクトアップグレード時に意図せずストレージ変数のレイアウトが変わってしまうのを防ぐ。
code:コントラクトアップグレード時の注意点
* ストレージ変数の変更や削除をしてはいけない
* エンドユーザのDEXや交換所はその変更を知らないので、今まで使ってたfunctionの挙動が変わったりして障害を引き起こす可能性がある
* 変数の追加は問題ない